package org.jeecg.modules.report;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.jeecg.modules.jmreport.api.data.IDataSetFactory;
import org.jeecg.modules.jmreport.desreport.model.JmPage;
import org.jeecg.modules.order.entity.Order;
import org.jeecg.modules.order.mapper.OrderMapper;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.zixishi.entity.Seat;
import org.jeecg.modules.zixishi.entity.Zixishi;
import org.jeecg.modules.zixishi.mapper.ZixishiMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component("SeatHoursReport")
@Slf4j
public class SeatHoursReport implements IDataSetFactory{

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private ZixishiMapper zixishiMapper;

    @SneakyThrows
    @Override
    public List<Map<String, Object>> createData(Map<String, Object> map) {
        Object monthBegin = map.get("month_begin");
        Object monthEnd = map.get("month_end");
        String monthBeginStr = monthBegin == null? "1990-01-01":"" + monthBegin;
        String monthEndStr = monthEnd == null? "1990-01-01":"" + monthEnd;
        List<Map<String,Object>> retData = new ArrayList<>();
        MPJLambdaWrapper<Order> queryWrapper = new MPJLambdaWrapper<Order>()
                .selectAll(Order.class)
                .selectAs(Zixishi::getName,"zixishiname")
                .selectAs(Seat::getName,"seatname")
                .leftJoin(Zixishi.class, Zixishi::getId, Order::getZixishiId)
                .leftJoin(Seat.class, Seat::getId, Order::getSeatId)
                .in(Order::getOrderStatus,Arrays.asList("1","2","3"))
                .ge(!StringUtils.equals("1990-01-01",monthBeginStr),Order::getCreateTime,DateUtil.beginOfDay(new SimpleDateFormat("yyyy-MM-dd").parse(monthBeginStr)))
                .le(!StringUtils.equals("1990-01-01",monthEndStr),Order::getCreateTime, DateUtil.endOfDay(new SimpleDateFormat("yyyy-MM-dd").parse( monthEndStr)))
                .ge(null == monthBegin && null == monthEnd, Order::getCreateTime,DateUtil.beginOfDay(new Date()));
        List<Order> orders = orderMapper.selectList(queryWrapper);

        if(CollectionUtil.isNotEmpty(orders)){
            List<Zixishi> zixishiList = zixishiMapper.selectList(null);
            Map<String, Map> zixishiMap = new HashMap<>();
            if(CollectionUtil.isNotEmpty(zixishiList)){
                for(Zixishi zixishi:zixishiList){
                    Date start = new SimpleDateFormat("HH:mm:ss").parse(zixishi.getStarttime());
                    Date end = new SimpleDateFormat("HH:mm:ss").parse(zixishi.getEndtime());
                    long hours = DateUtil.between(start,end, DateUnit.HOUR,false);

                    zixishiMap.put(zixishi.getId(),new HashMap(){{
                        put("name",zixishi.getName());
                        put("starttime",zixishi.getStarttime());
                        put("endtime",zixishi.getEndtime());
                        put("hours",hours<0?hours+24:hours);
                    }});
                }
            }
            List<Order> allOrders = new ArrayList<>();
            for(Order order:orders){
                if(StringUtils.equals("date",order.getReserveType())){
                    Map m = zixishiMap.get(order.getZixishiId());
                    Integer hours = Integer.parseInt("" + m.get("hours"));
                    String starttime = "" + m.get("starttime");
                    String endtime = "" + m.get("endtime");
                    Date start = order.getStartTime();
                    Date end = order.getEndTime();
                    double days = DateUtil.betweenDay(start,end,true);
                    for(int i=0;i<=days;i++){
                        Order tmpOrder = new Order();
                        BeanUtils.copyProperties(order,tmpOrder);
                        tmpOrder.setStartTime(new Date(start.getTime() + (i*1000 * 60 * 60 * 24L)));
                        tmpOrder.setEndTime(DateUtils.addHours(tmpOrder.getStartTime(),hours));
                        tmpOrder.setHours(hours);
                        tmpOrder.setMonth(new SimpleDateFormat("yyyy-MM-dd").format(tmpOrder.getStartTime()));
                        if(tmpOrder.getStartTime().compareTo(order.getEndTime())<0){
                            allOrders.add(tmpOrder);
                        }
                    }
                }else{
                    order.setHours(Integer.parseInt("" + DateUtil.between(order.getStartTime(),order.getEndTime(),DateUnit.HOUR,true)));
                    order.setMonth(new SimpleDateFormat("yyyy-MM-dd").format(order.getStartTime()));
                    allOrders.add(order);
                }
            }

            Function<Order, List<Object>> keyExtractor = o ->
                    Arrays.asList(o.getZixishiId(), o.getSeatId(), o.getSeatname(), o.getMonth());

            Map<List<Object>, IntSummaryStatistics> hoursData = allOrders.stream().collect(
                    Collectors.groupingBy(keyExtractor, Collectors.summarizingInt(Order::getHours)));


            hoursData.forEach((k,v)->{
                Map item = new HashMap();
                item.put("zixishi",zixishiMap.get(k.get(0)).get("name"));
                item.put("month",k.get(3));
                item.put("seatname",k.get(2));
                item.put("hours",v.getSum());
                item.put("cnt",v.getCount());
                BigDecimal h = new BigDecimal(v.getSum());
                BigDecimal hours = new BigDecimal("" + zixishiMap.get(k.get(0)).get("hours"));
                h = h.divide(hours,2,BigDecimal.ROUND_HALF_UP);
                item.put("p",(h.floatValue()*100) + "%");
                retData.add(item);
            });
        }
        return retData.stream().sorted(Comparator.comparing((Map d) -> (Integer.parseInt("" + d.get("hours")))).reversed()).collect(Collectors.toList());
    }

    @Override
    public JmPage createPageData(Map<String, Object> map) {

        return null;
    }
}
